home *** CD-ROM | disk | FTP | other *** search
/ Resource for Source: Assembly / assembly resource for source.iso / assem05 / cardfile.asm < prev    next >
Assembly Source File  |  1995-11-01  |  93KB  |  1,899 lines

  1.     page 60,132
  2.  
  3. ;CARDFILE.COM for the IBM Personal Computer - 1987 by Jeff Prosise
  4. ;
  5. bios_data     segment at 40h
  6. rs232_base    dw 4 dup (?)                  ;UART base addresses
  7.               org 4Ah
  8. crt_cols      dw ?                          ;number of display columns
  9.               org 4Eh
  10. crt_start     dw ?                          ;video page offset address
  11.               org 63h
  12. addr_6845     dw ?                          ;CRTC base address
  13.               org 87h
  14. infobyte      label word
  15. ega_info      db ?                          ;EGA info byte
  16. bios_data     ends
  17. ;
  18. code          segment para public 'code'
  19.               assume cs:code
  20.               org 100h
  21. begin:        jmp init1                     ;goto initialization code
  22. ;
  23. program            db "Cardfile 1.0 "
  24. copyright          db "(c) 1987 Ziff Communications Co.",13,10
  25.                    db "Hotkey is ALT-RIGHT SHIFT$",1Ah
  26. author             db "Jeff Prosise"
  27. ;
  28. dos_segment        dw ?                     ;segment of internal DOS flags
  29. indos_offset       dw ?                     ;offset of INDOS flag
  30. errflag_offset     dw ?                     ;offset of critical error flag
  31. program_status     db 0                     ;popup status
  32. flag_10h           db 0                     ;status of interrupt 10h
  33. flag_13h           db 0                     ;status of interrupt 13h
  34. request_flag       db 0                     ;status of processing request
  35. ss_register        dw ?                     ;SS register storage
  36. sp_register        dw ?                     ;SP register storage
  37. oldpsp             dw ?                     ;PSP segment storage
  38. ;
  39. maxrec             db 255                   ;maximum number of records
  40. recptr             db 1                     ;current record number
  41. numrec             db 0                     ;number of records
  42. adapter            db ?                     ;0=MDA, 1=CGA, 2=EGA
  43. video_segment      dw ?                     ;video segment address
  44. border_attr        db ?                     ;window border attribute
  45. text_attr          db ?                     ;window text attribute
  46. menu_attr          db ?                     ;menu line attribute
  47. record_attr        db ?                     ;record display attribute
  48. video_page         db ?                     ;current video page
  49. cursor_mode        dw ?                     ;cursor shape
  50. cursor_pos         dw ?                     ;cursor position
  51. cursor_addr        dw ?                     ;cursor CRTC address
  52. new_cursor         dw ?                     ;Cardfile cursor shape
  53. dos_version        db ?                     ;DOS version number
  54. slotno             db ?                     ;record position
  55. reload             db ?                     ;reload data file flag
  56. zflag              db ?                     ;critical error flag change status
  57. fileflag           db 0                     ;filespec validity indicator
  58. record_length      db 192                   ;record length in bytes
  59. ;
  60. comport            dw 0                     ;COM1
  61. initstr            db 10000011b             ;1200 baud, N81 data format
  62. dialstr            db "ATDT",0              ;Hayes Smartmodem dial string
  63. hangupstr          db "ATH0",13,0           ;Hayes Smartmodem hangup string
  64. ;
  65. jump_table         dw offset create              ;vector dispatch table
  66.                    dw offset edit
  67.                    dw offset delete
  68.                    dw offset search
  69.                    dw offset save
  70.                    dw offset dial
  71. ;
  72. titles             db 32,"Name",32,32,"Addr",14 dup (32),"Phone",32,"Note",32
  73. menuline1          db "F1-New F2-Ed F3-Del F4-Sch F5-Sv F6-Dial",0
  74. menuline2          db "Press ENTER to delete, ESC to abort",0
  75. menuline3          db "Press F1 to validate new entry",0
  76. menuline4          db "Find:",0
  77. menuline5          db "Press ENTER to continue, ESC to end",0
  78. menuline6          db "Search key not found. Press ESC",0
  79. menuline7          db "No room for additional records",0
  80. menuline8          db "Disk full",0
  81. menuline9          db "Press F1 to validate changes",0
  82. menuline10         db "Pick up phone and press spacebar",0
  83. menuline11         db "Error saving file",0
  84. menuline12         db "Modem not ready",0
  85. menuline13         db "File:",0
  86. ;
  87. timer_int          label dword              ;old interrupt 8 vector
  88. old8h              dw 2 dup (?)
  89. keyboard_int       label dword              ;old interrupt 9 vector
  90. old9h              dw 2 dup (?)
  91. video_int          label dword              ;old interrupt 10h vector
  92. old10h             dw 2 dup (?)
  93. bdisk_int          label dword              ;old interrupt 13h vector
  94. old13h             dw 2 dup (?)
  95. bp_int             label dword              ;old interrupt 28h vector
  96. old28h             dw 2 dup (?)
  97. ;
  98. old1Bh_segment     dw ?                     ;old interrupt 1Bh segment
  99. old1Bh_offset      dw ?                     ;old interrupt 1Bh offset
  100. old23h_segment     dw ?                     ;old interrupt 23h segment
  101. old23h_offset      dw ?                     ;old interrupt 23h offset
  102. old24h_segment     dw ?                     ;old interrupt 24h segment
  103. old24h_offset      dw ?                     ;old interrupt 24h offset
  104. ;
  105. color_attr         db 0,0B8h,1Fh,6Eh,6Eh,6Fh
  106. mono_attr          db 0,0B0h,70h,07h,07h,07h
  107. enable_values      db 2Ch,28h,2Dh,29h,2Ah,2Eh,1Eh
  108. key_table          db "QWERTYUIOP",0,0,0,0
  109.                    db "ASDFGHJKL",0,0,0,0,0
  110.                    db "ZXCVBNM"
  111. ;
  112. ;------------------------------------------------------------------------------
  113. ;Execution comes here thru interrupt 9 every time a key is pressed or released.
  114. ;------------------------------------------------------------------------------
  115. keyboard      proc near
  116.               sti                           ;set interrupt enable flag
  117.               pushf                         ;push flags to simulate INT
  118.               call keyboard_int             ;call keyboard handling routine
  119.               push ax                       ;save AX
  120.               mov ah,2                      ;get keyboard shift status
  121.               int 16h
  122.               and al,0Fh                    ;mask off upper 4 bits
  123.               cmp al,9                      ;Alt/Rt-Shift pressed?
  124.               pop ax                        ;restore AX
  125.               jne kb_exit                   ;no, then exit
  126.               cmp program_status,0          ;popup routine already active?
  127.               jne kb_exit                   ;yes, then ignore keypress
  128.               mov request_flag,18           ;set request flag
  129. kb_exit:      iret
  130. keyboard      endp
  131. ;
  132. ;------------------------------------------------------------------------------
  133. ;Interrupt 8 handling routine.
  134. ;------------------------------------------------------------------------------
  135. timer         proc near
  136.               pushf                         ;call BIOS routine
  137.               call timer_int
  138.               cmp request_flag,0            ;flag set?
  139.               je timer_exit                 ;no, then exit
  140.               cmp flag_10h,0                ;video flag set?
  141.               jne dectime                   ;yes, then exit
  142.               cmp flag_13h,0                ;disk flag set?
  143.               jne dectime                   ;yes, then exit
  144.               push es                       ;save ES and DI
  145.               push di
  146.               mov es,dos_segment            ;check INDOS flag
  147.               mov di,indos_offset
  148.               cmp byte ptr es:[di],0
  149.               jne poptime                   ;exit if it's set
  150.               mov di,errflag_offset         ;check critical error flag
  151.               cmp byte ptr es:[di],0
  152.               jne poptime                   ;exit if it's set
  153.               pop di                        ;restore registers
  154.               pop es
  155.               mov request_flag,0            ;zero request flag
  156.               call main                     ;call body of program
  157. timer_exit:   iret
  158. poptime:      pop di                        ;clean up the stack
  159.               pop es
  160. dectime:      dec request_flag              ;decrement request flag
  161.               iret
  162. timer         endp
  163. ;
  164. ;------------------------------------------------------------------------------
  165. ;Interrupt 10h handling routine.
  166. ;------------------------------------------------------------------------------
  167. video         proc near
  168.               pushf                         ;push flags onto stack
  169.               inc flag_10h                  ;increment flag
  170.               call video_int                ;call BIOS routine
  171.               dec flag_10h                  ;decrement flag
  172.               iret
  173. video         endp
  174. ;
  175. ;------------------------------------------------------------------------------
  176. ;Interrupt 13h handling routine.
  177. ;------------------------------------------------------------------------------
  178. bdisk         proc far
  179.               pushf                         ;push flags onto stack
  180.               inc flag_13h                  ;set 'busy' flag
  181.               call bdisk_int                ;call BIOS routine
  182.               pushf                         ;save output flags
  183.               dec flag_13h                  ;clear flag
  184.               popf                          ;restore output flags
  185.               ret 2                         ;exit without destroying flags
  186. bdisk         endp
  187. ;
  188. ;------------------------------------------------------------------------------
  189. ;Interrupt 28h handling routine.
  190. ;------------------------------------------------------------------------------
  191. backproc      proc near
  192.               pushf                         ;call original routine
  193.               call bp_int
  194.               cmp request_flag,0            ;request flag clear?
  195.               je bp_exit                    ;yes, then exit
  196.               cmp flag_10h,0                ;video flag set?
  197.               jne bp_exit                   ;yes, then exit
  198.               cmp flag_13h,0                ;disk flag set?
  199.               jne bp_exit                   ;yes, then exit
  200.               push es                       ;save ES and DI
  201.               push di
  202.               mov es,dos_segment            ;check critical error flag
  203.               mov di,errflag_offset
  204.               cmp byte ptr es:[di],0
  205.               pop di                        ;clean up the stack
  206.               pop es
  207.               jne bp_exit
  208.               mov request_flag,0            ;clear request flag
  209.               call main                     ;call main routine
  210. bp_exit:      iret                          ;done - exit
  211. backproc      endp
  212. ;
  213. ;------------------------------------------------------------------------------
  214. ;Interrupt 24h handling routine (DOS 3.X only).
  215. ;------------------------------------------------------------------------------
  216. ioerr         proc near
  217.               mov al,3                      ;fail the call in progress
  218. ioexit:       iret                          ;give control back to DOS
  219. ioerr         endp
  220. ;
  221. ;------------------------------------------------------------------------------
  222. ;MAIN is the routine called to pop up and manipulate the CardFile window.
  223. ;------------------------------------------------------------------------------
  224. main          proc near
  225.               mov program_status,1          ;set program active flag
  226.               cli                           ;make sure interrupts are off
  227.               mov ss_register,ss            ;save stack registers
  228.               mov sp_register,sp
  229.               push cs                       ;switch to internal stack
  230.               pop ss
  231.               mov sp,offset filespec
  232.               sti                           ;enable interrupts
  233.               push ax                       ;save other registers
  234.               push bx
  235.               push cx
  236.               push dx
  237.               push si
  238.               push di
  239.               push ds
  240.               push es
  241.               push bp
  242.               mov ah,15                     ;get video mode and page
  243.               int 10h
  244.               cmp al,3                      ;mode 0, 1, 2, or 3?
  245.               jbe main1                     ;yes, then continue
  246.               cmp al,7                      ;mode 7?
  247.               je main1                      ;yes, then continue
  248. ;
  249. ;Restore registers and stack before exit.
  250. ;
  251. exit:         pop bp                        ;restore registers and exit
  252.               pop es
  253.               pop ds
  254.               pop di
  255.               pop si
  256.               pop dx
  257.               pop cx
  258.               pop bx
  259.               pop ax
  260.               cli                           ;interrupts off
  261.               mov ss,ss_register            ;switch to original stack
  262.               mov sp,sp_register
  263.               sti                           ;interrupts on
  264.               mov program_status,0          ;clear status flag
  265.               ret
  266. ;
  267. ;Set DS and ES segment registers.
  268. ;
  269. main1:        push cs                       ;set DS to code segment
  270.               pop ds
  271.               assume ds:code
  272.               mov ax,bios_data              ;point ES to BIOS data
  273.               mov es,ax
  274.               assume es:bios_data
  275.               cmp crt_cols,80               ;at least 80 columns displayed?
  276.               jb exit                       ;no, then exit
  277. ;
  278. ;Save needed video parameters.
  279. ;
  280.               mov video_page,bh             ;active video page
  281.               mov ah,3                      ;get cursor mode and location
  282.               int 10h
  283.               mov cursor_mode,cx
  284.               mov cursor_pos,dx
  285.               mov dx,addr_6845              ;get CRTC base address
  286.               push dx                       ;save it for later
  287.               mov al,14                     ;specify register number
  288.               out dx,al
  289.               inc dx                        ;point DX to data port
  290.               in al,dx                      ;read high byte of address
  291.               mov ah,al                     ;save it
  292.               dec dx                        ;back to index register
  293.               mov al,15                     ;specify register number
  294.               out dx,al
  295.               inc dx                        ;back to data port
  296.               in al,dx                      ;read low byte of address
  297.               mov cursor_addr,ax            ;save cursor address
  298. ;
  299. ;Determine whether an EGA is present and active in the system.
  300. ;
  301.               mov ah,12h                    ;see if EGA is present
  302.               mov bl,10h
  303.               int 10h
  304.               cmp bl,10h                    ;did BL return unchanged?
  305.               je main2                      ;yes, then there's no EGA here
  306.               test ega_info,8               ;is the EGA currently active?
  307.               jnz main2                     ;no, then branch
  308.               mov adapter,2                 ;set ADAPTER for EGA
  309.               push bx                       ;save BX
  310.               mov ax,1130h                  ;get number of scan lines per char
  311.               int 10h
  312.               dec cl                        ;form cursor definition in CX
  313.               mov ch,cl
  314.               sub ch,2
  315.               mov new_cursor,cx             ;save cursor definition
  316.               mov si,offset color_attr      ;point SI to color parms
  317.               pop bx                        ;retrieve BX
  318.               or bh,bh                      ;EGA attached to color monitor?
  319.               je main4                      ;yes, then branch
  320.               mov si,offset mono_attr       ;no, then point SI to mono parms
  321.               jmp short main4
  322. ;
  323. ;Determine whether the active video adapter is a CGA or an MDA.
  324. ;
  325. main2:        test addr_6845,40h            ;is bit 6 of the CRTC address set?
  326.               jz main3                      ;no, then it's monochrome
  327.               mov adapter,1                 ;set ADAPTER for a CGA
  328.               mov new_cursor,0607h          ;define cursor shape
  329.               mov si,offset color_attr      ;point SI to color parms
  330.               jmp short main4
  331. main3:        mov adapter,0                 ;set ADAPTER for an MDA
  332.               mov new_cursor,0B0Ch          ;define monochrome cursor
  333.               mov si,offset mono_attr       ;point SI to mono parms
  334. ;
  335. ;Set video parameters for color or monochrome.
  336. ;
  337. main4:        push cs                       ;set ES to the code segment
  338.               pop es
  339.               assume es:nothing
  340.               mov di,offset video_segment   ;point DI to destination
  341.               mov cx,3                      ;3 words to move
  342.               cld                           ;clear DF
  343.               rep movsw                     ;transfer the values
  344. ;
  345. ;Save the current active PSP address and activate this PSP.
  346. ;
  347.               push es                       ;save ES
  348.               mov zflag,0                   ;clear flag
  349.               cmp dos_version,2             ;DOS version 2.X?
  350.               jne main5
  351.               mov es,dos_segment            ;point ES:DI to INDOS
  352.               mov di,indos_offset
  353.               cmp byte ptr es:[di],0        ;INDOS clear?
  354.               je main5                      ;yes, then branch
  355.               mov di,errflag_offset         ;point ES:DI to error flag
  356.               cmp byte ptr es:[di],0        ;critical error flag clear?
  357.               jne main5                     ;no, then branch
  358.               mov byte ptr es:[di],1        ;set critical error flag manually
  359.               mov zflag,1                   ;set change flag
  360. main5:        mov ah,51h                    ;get current PSP segment
  361.               int 21h
  362.               mov oldpsp,bx                 ;save it
  363.               mov ah,50h                    ;make this the active PSP
  364.               push cs
  365.               pop bx
  366.               int 21h
  367.               cmp zflag,0                   ;ZFLAG clear?
  368.               je main6                      ;yes, then branch
  369.               mov di,errflag_offset         ;point ES:DI to error flag
  370.               mov byte ptr es:[di],0        ;restore error flag value
  371. main6:        pop es                        ;restore ES
  372. ;
  373. ;Reset the interrupt 1Bh, 23h, and 24h vectors and open the CardFile window.
  374. ;
  375.               call ioset                    ;reset interrupt vectors
  376.               cmp adapter,1                 ;disable CGA video
  377.               jne main7
  378.               call disable_cga
  379. main7:        call save_screen              ;save memory to be overwritten
  380.               call make_screen              ;open the CardFile window
  381.               cmp adapter,1                 ;enable CGA video
  382.               jne main8
  383.               call enable_cga
  384. main8:        mov ah,1                      ;hide the cursor
  385.               mov ch,20h
  386.               int 10h
  387.               cmp numrec,0                  ;any records in memory?
  388.               je main10                     ;no, then branch
  389.               call show_record              ;display current record
  390. ;
  391. ;Wait for a keystroke and exit when ESC is pressed.
  392. ;
  393. main10:       call getkey                   ;wait for a keypress
  394.               or al,al                      ;extended code entered?
  395.               je main12                     ;yes, then branch
  396.               cmp al,13                     ;ENTER pressed?
  397.               jne main11                    ;no, then branch around
  398.               cmp numrec,2                  ;at least 2 records?
  399.               jb main10                     ;no, then ignore keypress
  400.               jmp short main20              ;yes, then do a PgDn
  401. main11:       cmp al,27                     ;ESC pressed?
  402.               jne main10                    ;no, then ignore keypress
  403.               jmp short escape              ;yes, then close window and exit
  404. ;
  405. ;An extended code was entered.  Check for an Alt-character key combination.
  406. ;
  407. main12:       cmp ah,16                     ;scan code < 16 (Alt-Q)?
  408.               jb main10                     ;yes, then ignore it
  409.               cmp ah,50                     ;scan code > 50 (Alt-M)?
  410.               ja main13                     ;yes, then branch and continue
  411.               call qsearch                  ;do quick search
  412.               jmp main10                    ;return for another keypress
  413. ;
  414. ;Check for a press of any function key F1 through F6.
  415. ;
  416. main13:       cmp ah,59                     ;scan code < 59 (F1)?
  417.               jb main10                     ;yes, then ignore it
  418.               cmp ah,64                     ;scan code > 64 (F6)?
  419.               ja main14                     ;yes, then branch and continue
  420.               sub ah,59                     ;normalize scan code
  421.               mov bl,ah                     ;transfer result
  422.               xor bh,bh                     ;byte to word in BX
  423.               shl bx,1                                     ;double index in BX
  424.               call word ptr cs:[offset jump_table+bx]      ;call routine
  425.               jmp main10                                   ;return
  426. ;
  427. ;Check for Home, End, PgUp, and PgDn.
  428. ;
  429. main14:       cmp numrec,2                  ;are there at least 2 records?
  430.               jb main10                     ;no, then ignore keypress
  431.               cmp ah,71                     ;Home key?
  432.               jne main16                    ;no, then branch
  433.               mov recptr,1                  ;set pointer to first record
  434. main15:       call show_record              ;display record
  435.               jmp main10                    ;return
  436. main16:       cmp ah,79                     ;End key?
  437.               jne main18                    ;no, then branch
  438. main17:       mov al,numrec                 ;get number of records
  439.               mov recptr,al                 ;set pointer to last record
  440.               jmp main15                    ;display record
  441. main18:       cmp ah,73                     ;PgUp key?
  442.               jne main19                    ;no, then branch
  443.               dec recptr                    ;adjust pointer
  444.               cmp recptr,0                  ;wrap around if necessary
  445.               jne main15
  446.               jmp main17
  447. main19:       cmp ah,81                     ;PgDn key?
  448.               jne main10                    ;no, then ignore keypress
  449. main20:       mov al,numrec                 ;presently showing last record?
  450.               cmp al,recptr
  451.               je main21                     ;yes, then branch
  452.               inc recptr                    ;no, then advance pointer
  453.               jmp main15                    ;display record
  454. main21:       mov recptr,1                  ;set pointer to first record
  455.               jmp main15                    ;display record
  456. ;
  457. ;Restore interrupt vectors and former active PSP.
  458. ;
  459. escape:       mov ah,50h                    ;restore active PSP label
  460.               mov bx,oldpsp
  461.               int 21h
  462.               call ioreset                  ;restore interrupt vectors
  463. ;
  464. ;Close the Cardfile window in preparation for exit.
  465. ;
  466.               cmp adapter,1                 ;disable CGA video
  467.               jne esc1
  468.               call disable_cga
  469. esc1:         call restore_screen           ;restore screen contents
  470.               cmp adapter,1                 ;enable CGA video
  471.               jne esc2
  472.               call enable_cga
  473. ;
  474. ;Restore the cursor's former position in the BIOS data area and the CRTC.
  475. ;
  476. esc2:         mov ah,2                      ;set cursor position thru BIOS
  477.               mov bh,video_page
  478.               mov dx,cursor_pos
  479.               int 10h
  480.               pop dx                        ;recover CRTC base address
  481.               mov cx,cursor_addr            ;restore cursor address
  482.               mov al,14                     ;CRTC register number
  483.               out dx,al
  484.               inc dx
  485.               mov al,ch
  486.               out dx,al                     ;write high byte of address
  487.               dec dx
  488.               mov al,15                     ;CRTC register number
  489.               out dx,al
  490.               inc dx
  491.               mov al,cl
  492.               out dx,al                     ;write low byte
  493. ;
  494. ;Display the cursor, bypassing EGA cursor emulation logic, and exit.
  495. ;
  496.               cmp adapter,2                 ;EGA on board?
  497.               jne esc3                      ;no, then branch
  498.               call show_cursor              ;retain current shape
  499.               jmp exit
  500. esc3:         mov ah,1                      ;restore cursor shape
  501.               mov cx,cursor_mode
  502.               int 10h
  503.               jmp exit                      ;exit
  504. main          endp
  505. ;
  506. ;------------------------------------------------------------------------------
  507. ;SAVE_SCREEN saves the contents of the screen that underlie the window.
  508. ;------------------------------------------------------------------------------
  509. linesum       dw ?
  510. video_address dw ?
  511. ;
  512. save_screen   proc near
  513.               push ds                       ;save DS
  514.               mov ax,bios_data              ;point it to BIOS data area
  515.               mov ds,ax
  516.               assume ds:bios_data
  517.               mov ax,crt_cols               ;get number of display columns
  518.               mov linesum,ax                ;calculate distance from end of
  519.               sub linesum,44                ;  one line to start of next
  520.               shl linesum,1
  521.               mov bl,6                      ;calculate starting address
  522.               mul bl                        ;result in AX
  523.               shl ax,1                      ;double result for attr bytes
  524.               add ax,36                     ;add line offset
  525.               mov si,ax                     ;transfer to SI
  526.               add si,crt_start              ;add page offset
  527.               mov video_address,si          ;save offset address
  528.               mov ds,video_segment          ;then set DS to the video segment
  529.               mov di,offset screen_buffer   ;point DI to storage buffer
  530.               mov cx,10                     ;10 lines to save
  531. save1:        push cx                       ;save line count
  532.               mov cx,44                     ;44 characters per line
  533.               rep movsw                     ;transfer one line to storage
  534.               pop cx                        ;retrieve line count
  535.               add si,linesum                ;point SI to next video line
  536.               loop save1                    ;loop until all lines are saved
  537.               pop ds                        ;restore DS
  538.               assume ds:code
  539.               ret                           ;exit
  540. save_screen   endp
  541. ;
  542. ;------------------------------------------------------------------------------
  543. ;RESTORE_SCREEN writes the stored screen image to video memory.
  544. ;------------------------------------------------------------------------------
  545. restore_screen proc near
  546.               push es                       ;save ES register value
  547.               mov di,video_address          ;point DI to starting video offset
  548.               mov es,video_segment          ;point ES to video memory
  549.               mov si,offset screen_buffer   ;point DS:SI to screen image
  550.               mov cx,10                     ;10 lines to restore
  551. restore1:     push cx                       ;save line count
  552.               mov cx,44                     ;44 characters per line
  553.               rep movsw                     ;restore one line
  554.               pop cx                        ;retrieve line count
  555.               add di,linesum                ;set DI to next video line
  556.               loop restore1                 ;loop until done
  557.               pop es                        ;restore ES
  558.               ret
  559. restore_screen endp
  560. ;
  561. ;------------------------------------------------------------------------------
  562. ;MAKE_SCREEN writes an image of the CardFile window to video memory.
  563. ;------------------------------------------------------------------------------
  564. make_screen   proc near
  565.               push es                       ;save ES
  566.               mov es,video_segment          ;point ES:DI to video memory
  567.               mov di,video_address
  568.               mov al,218                    ;line no. 1
  569.               mov ah,border_attr
  570.               stosw
  571.               mov al,196
  572.               mov cx,42
  573.               rep stosw
  574.               mov al,191
  575.               stosw
  576.               add di,linesum
  577.               mov si,offset titles          ;lines 2 thru 7
  578.               mov cx,6                      ;6 lines
  579. make1:        push cx
  580.               call formline
  581.               add di,linesum
  582.               pop cx
  583.               loop make1
  584.               mov al,179                    ;line no. 8
  585.               stosw
  586.               push ax
  587.               mov al,32
  588.               mov ah,text_attr
  589.               stosw
  590.               push ax
  591.               mov al,196
  592.               mov cx,40
  593.               rep stosw
  594.               pop ax
  595.               stosw
  596.               pop ax
  597.               stosw
  598.               add di,linesum
  599.               stosw                         ;line no. 9
  600.               push ax
  601.               mov al,32
  602.               mov ah,menu_attr
  603.               stosw
  604.               push ax
  605.               mov si,offset menuline1
  606.               mov cx,40
  607. make2:        lodsb
  608.               stosw
  609.               loop make2
  610.               pop ax
  611.               stosw
  612.               pop ax
  613.               stosw
  614.               add di,linesum
  615.               mov al,192                    ;line no. 10
  616.               stosw
  617.               mov al,196
  618.               mov cx,42
  619.               rep stosw
  620.               mov al,217
  621.               stosw
  622.               pop es                        ;restore ES
  623.               ret
  624. make_screen   endp
  625. ;
  626. ;------------------------------------------------------------------------------
  627. ;FORMLINE is called by MAKE_SCREEN to help with the dirty work.
  628. ;------------------------------------------------------------------------------
  629. formline      proc near
  630.               mov al,179                    ;write border character
  631.               mov ah,border_attr
  632.               stosw
  633.               push ax                       ;save it for later
  634.               mov cx,6                      ;do next 6 characters
  635.               mov ah,text_attr
  636. form1:        lodsb
  637.               stosw
  638.               loop form1
  639.               mov al,32                     ;add 2 blanks
  640.               stosw
  641.               stosw
  642.               mov ah,record_attr            ;then add 34 blank characters
  643.               mov cx,34
  644.               rep stosw
  645.               pop ax                        ;finish with border character
  646.               stosw
  647.               ret
  648. formline      endp
  649. ;
  650. ;------------------------------------------------------------------------------
  651. ;QSEARCH pages to the record whose first character matches the Alt key pressed.
  652. ;------------------------------------------------------------------------------
  653. qsearch       proc near
  654.               cmp numrec,2                  ;at least 2 records to search?
  655.               jb qs3                        ;no, then exit
  656.               mov al,ah                     ;transfer scan code to AL
  657.               sub al,16                     ;normalize it
  658.               mov bx,offset key_table       ;address table of equivalents
  659.               xlat                          ;get corresponding ASCII code
  660.               mov dl,al                     ;transfer it to DL
  661.               mov cl,numrec                 ;get record count in CX
  662.               xor ch,ch
  663.               mov al,1                      ;initialize record index
  664. qs1:          push ax                       ;save index
  665.               push cx                       ;save count
  666.               call record_address           ;get address of current record
  667.               cmp [di],dl                   ;compare characters
  668.               pop cx                        ;retrieve count and index
  669.               pop ax
  670.               jae qs2                       ;end search
  671.               inc al                        ;increment index
  672.               loop qs1                      ;loop back for next record
  673.               dec al                        ;search exhausted
  674. qs2:          cmp al,recptr                 ;record already showing?
  675.               je qs3                        ;yes, then exit
  676.               mov recptr,al                 ;no, then change display
  677.               call show_record
  678. qs3:          ret
  679. qsearch       endp
  680. ;
  681. ;------------------------------------------------------------------------------
  682. ;SEARCH searches data for occurrence of a string input by the user.
  683. ;------------------------------------------------------------------------------
  684. strlen        db ?                          ;string length
  685. passes        db ?                          ;number of search loops
  686. ;
  687. search        proc near
  688.               cmp numrec,0                  ;any records to search?
  689.               je search_exit                ;no, then exit
  690.               mov si,offset menuline4       ;prepare menu line for input
  691.               call write_menu
  692.               xor di,di                     ;read string from keyboard
  693.               mov dx,0E1Ah
  694.               mov cl,32
  695.               call readln
  696.               or cl,cl                      ;anything entered?
  697.               jne search1                   ;yes, then continue
  698. search_exit:  mov si,offset menuline1       ;restore menu line and exit
  699.               call write_menu
  700.               ret
  701. ;
  702. ;Set search parameters and begin the scan.
  703. ;
  704. search1:      mov strlen,cl                 ;save string length
  705.               mov ch,33                     ;determine no. of passes per line
  706.               sub ch,cl
  707.               mov passes,ch                 ;save it
  708.               mov al,recptr                 ;start search at current record
  709.               mov cl,numrec                 ;set max search length
  710.               xor ch,ch
  711. search2:      push ax                       ;save record number
  712.               push cx                       ;save record count
  713.               call record_address           ;get address of current record
  714.               mov cx,6                      ;6 lines per record
  715. search3:      push cx                       ;save line count
  716.               push di                       ;save line address
  717.               mov cl,passes                 ;set number of passes per line
  718.               xor ch,ch
  719. search4:      push cx                       ;save pass count
  720.               push di                       ;save search address within line
  721.               mov cl,strlen                 ;number of bytes to compare
  722.               xor ch,ch
  723.               xor si,si                     ;point SI to input buffer
  724. search5:      lodsb                         ;get a byte from the input buffer
  725.               and al,0DFh                   ;capitalize it
  726.               mov bl,es:[di]                ;get a byte from the record
  727.               and bl,0DFh                   ;capitalize it
  728.               inc di                        ;advance pointer
  729.               cmp al,bl                     ;are the two bytes identical?
  730.               jne nextpos                   ;no, then try next position
  731.               loop search5                  ;yes, then try next byte
  732. ;
  733. ;A match was found.  Clean up the stack and display the record.
  734. ;
  735.               add sp,10                     ;delete last 5 words PUSHed
  736.               pop ax                        ;retrieve current record number
  737.               push ax                       ;push it back onto the stack
  738.               mov cl,numrec                 ;restart the record counter
  739.               xor ch,ch
  740.               inc cx
  741.               push cx                       ;shove it onto the stack
  742.               mov recptr,al                 ;set current record to this one
  743.               call show_record              ;display new record
  744.               mov si,offset menuline5       ;display new menu line
  745.               call write_menu
  746. searchkey:    call getkey                   ;wait for a keypress
  747.               cmp al,13                     ;ENTER key?
  748.               je nextrec                    ;yes, then continue search
  749.               cmp al,27                     ;ESC key?
  750.               jne searchkey                 ;no, then ignore the keypress
  751.               pop cx                        ;clean up the stack
  752.               pop ax
  753.               jmp search_exit               ;exit
  754. ;
  755. ;Advance to the next position and continue the string search.
  756. ;
  757. nextpos:      pop di                        ;retrieve address
  758.               pop cx                        ;retrieve pass count
  759.               inc di                        ;advance to next position on line
  760.               loop search4                  ;loop back for another try
  761. nextline:     pop di                        ;retrieve line address
  762.               pop cx                        ;retrieve line count
  763.               add di,32                     ;advance pointer to next line
  764.               loop search3                  ;loop back
  765. nextrec:      pop cx                        ;retrieve record count
  766.               pop ax                        ;retrieve current record number
  767.               cmp al,numrec                 ;currently on last record?
  768.               je reset                      ;yes, then wrap around
  769.               inc al                        ;no, then advance record pointer
  770.               jmp short next1
  771. reset:        mov al,1                      ;reset record pointer
  772. next1:        loop search2                  ;reenter main loop
  773. ;
  774. ;All records were searched and no match was found.
  775. ;
  776.               mov si,offset menuline6       ;print message
  777.               call write_menu
  778. search6:      call getkey                   ;wait for a press of ESC
  779.               cmp al,27
  780.               jne search6
  781.               jmp search_exit               ;exit
  782. search        endp
  783. ;
  784. ;------------------------------------------------------------------------------
  785. ;DIAL dials the phone number currently displayed.
  786. ;------------------------------------------------------------------------------
  787. linectrl           db ?                     ;Line Control Register value
  788. divlsb             db ?                     ;baud rate divisor LSB
  789. divmsb             db ?                     ;baud rate divisor MSB
  790. intreg             db ?                     ;Interrupt Enable Register value
  791. ;
  792. dial          proc near
  793.               cmp numrec,0                  ;any records in memory?
  794.               jne dstart                    ;yes, then branch
  795. dial_exit:    ret                           ;no, then exit
  796. ;
  797. ;Save the current state of the COM port.
  798. ;
  799. dstart:       mov si,comport                ;get UART base address
  800.               shl si,1
  801.               push es                       ;save ES
  802.               mov ax,bios_data              ;then point it to BIOS data area
  803.               mov es,ax
  804.               assume es:bios_data
  805.               mov dx,rs232_base[si]
  806.               pop es                        ;restore ES
  807.               assume es:nothing
  808.               or dx,dx                      ;is this port installed?
  809.               je dial_exit                  ;no, then exit
  810.               add dx,3                      ;point DX to Line Control Register
  811.               push dx                       ;save the address
  812.               in al,dx                      ;read LCR
  813.               mov linectrl,al               ;store value for later
  814.               or al,80h                     ;set DLAB
  815.               out dx,al
  816.               sub dx,3                      ;point DX to Divisor LSB Register
  817.               in al,dx                      ;read it
  818.               mov divlsb,al                 ;save it
  819.               inc dx                        ;point DX to Divisor MSB Register
  820.               in al,dx                      ;read it
  821.               mov divmsb,al                 ;save it
  822.               mov al,linectrl               ;recover Line Control setting
  823.               and al,07Fh                   ;clear the high bit
  824.               add dx,2                      ;point DX back to Line Control
  825.               out dx,al                     ;clear DLAB
  826.               sub dx,2                      ;address Interrupt Enable Register
  827.               in al,dx                      ;read it
  828.               mov intreg,al                 ;and save it
  829. ;
  830. ;Initialize the COM port.
  831. ;
  832.               mov ah,0                      ;initialize COM port
  833.               mov al,initstr                ;baud rate and data format
  834.               mov dx,comport                ;COM port identifier
  835.               int 14h
  836. ;
  837. ;Dial the phone number.
  838. ;
  839.               mov si,offset dialstr         ;point DS:SI to 'ATDT' string
  840.               call sendcom                  ;output string to COM port
  841.               test ah,80h                   ;was the string sent?
  842.               jnz time_out                  ;no, then modem isn't ready
  843.               mov al,recptr                 ;get address of current record
  844.               call record_address
  845.               mov si,di
  846.               add si,128                    ;point SI to 'Phone' line
  847.               mov cx,32                     ;32 characters to check
  848. dial1:        lodsb                         ;get one character
  849.               cmp al,","                    ;is it a comma?
  850.               je dial2                      ;yes, then send it
  851.               cmp al,"0"                    ;less than ASCII zero?
  852.               jb dial3                      ;yes, then ignore it
  853.               cmp al,"9"                    ;greater than ASCII 9?
  854.               ja dial3                      ;yes, then ignore it
  855. dial2:        mov ah,1                      ;output byte to COM port
  856.               int 14h
  857.               test ah,80h                   ;was the byte successfully output?
  858.               jnz time_out                  ;no, then modem isn't ready
  859. dial3:        loop dial1                    ;loop until line is finished
  860.               mov ax,013Bh                  ;terminate with semicolon and CR
  861.               int 14h
  862.               mov ax,010Dh
  863.               int 14h
  864.               test ah,80h                   ;were the bytes transmitted?
  865.               jz dial5                      ;yes, then continue
  866. ;
  867. ;Display 'Modem not ready' message and wait for ESC to be pressed.
  868. ;
  869. time_out:     mov si,offset menuline12      ;print message
  870.               call write_menu
  871. dial4:        call getkey                   ;wait for a press of ESC
  872.               cmp al,27
  873.               jne dial4
  874.               jmp dial8
  875. ;
  876. ;Wait for a press of the spacebar, then force the modem to hang up.
  877. ;
  878. dial5:        mov si,offset menuline10      ;display 'Pick up phone...'
  879.               call write_menu
  880. dial6:        call getkey                   ;wait for a press of the spacebar
  881.               cmp al,32
  882.               jne dial6 
  883.               mov si,offset hangupstr       ;point SI to 'ATH0' string
  884.               mov dx,comport                ;specify COM port
  885.               call sendcom                  ;output it to the COM port
  886.               mov cx,8000h                  ;I/O delay
  887. dial7:        loop dial7
  888. ;
  889. ;Restore the COM port to its original state and exit.
  890. ;
  891. dial8:        pop dx                        ;retrieve UART address
  892.               mov al,80h                    ;set DLAB
  893.               out dx,al
  894.               sub dx,3                      ;point DX to Divisor LSB
  895.               mov al,divlsb                 ;reset it
  896.               out dx,al
  897.               inc dx                        ;point DX to MSB
  898.               mov al,divmsb                 ;reset it
  899.               out dx,al
  900.               add dx,2                      ;point DX to Line Control
  901.               xor al,al                     ;clear DLAB
  902.               out dx,al
  903.               sub dx,2                      ;point DX to Interrupt Enable
  904.               mov al,intreg                 ;restore it
  905.               out dx,al
  906.               add dx,2                      ;restore Line Control Register
  907.               mov al,linectrl
  908.               out dx,al
  909.               mov si,offset menuline1       ;restore menu line and exit
  910.               call write_menu
  911.               ret
  912. dial          endp
  913. ;
  914. ;------------------------------------------------------------------------------
  915. ;SENDCOM outputs an ASCIIZ string to the designated COM port.
  916. ;Entry:  DS:SI - string address        | Exit:  AH bit 7 clear - string sent
  917. ;        DX    - 0 = COM1, 1 = COM2    |        AH bit 7 set   - time out
  918. ;------------------------------------------------------------------------------
  919. sendcom       proc near
  920.               lodsb                         ;get a byte
  921.               or al,al                      ;zero terminator?
  922.               je comexit                    ;yes, then exit
  923.               mov ah,1                      ;output byte
  924.               int 14h
  925.               test ah,80h                   ;was byte transmitted?
  926.               jz sendcom                    ;yes, loop back for more
  927. comexit:      ret       ;exit
  928. sendcom       endp
  929. ;
  930. ;------------------------------------------------------------------------------
  931. ;EDIT allows the current record to be edited.
  932. ;------------------------------------------------------------------------------
  933. edit          proc near
  934.               cmp numrec,0                  ;any records to edit?
  935.               je edit1                      ;no, then exit
  936.               mov al,recptr                 ;get current record number
  937.               call record_address           ;get its address and position
  938.               mov slotno,al                 ;save position
  939.               push di                       ;save address
  940.               call delete_record            ;delete it
  941.               pop di                        ;recover address
  942.               push di                       ;save it again
  943.               mov si,offset menuline9       ;address menu line text
  944.               call edit_record              ;allow it to be edited
  945.               pop si                        ;place address in SI
  946.               jc no_entry                   ;branch if entry now blank
  947.               call find_position            ;determine logical position
  948.               mov bl,slotno                 ;retrieve physical position
  949.               call insert_record            ;insert record into the stack
  950.               mov recptr,cl                 ;modify current record number
  951. edit1:        ret                           ;exit
  952. no_entry:     cmp numrec,0                  ;any records left after deletion?
  953.               je edit1                      ;no, then we're done
  954.               mov al,numrec                 ;get number of records
  955.               cmp al,recptr                 ;RECPTR in range?
  956.               jae edit2                     ;yes, then branch
  957.               dec recptr                    ;no, then modify it
  958. edit2:        call show_record              ;display new current record
  959.               ret
  960. edit          endp
  961. ;
  962. ;------------------------------------------------------------------------------
  963. ;CREATE allows a new record to be created and inserted.
  964. ;------------------------------------------------------------------------------
  965. create        proc near
  966.               mov al,numrec                 ;retrieve number of records
  967.               cmp al,maxrec                 ;room for another record?
  968.               jne create1                   ;yes, then branch
  969.               mov si,offset menuline7       ;no, then print error message
  970.               call write_menu
  971. create0:      call getkey                   ;wait for a press of ESC
  972.               cmp al,27
  973.               jne create0
  974.               mov si,offset menuline1       ;restore menu line
  975.               call write_menu
  976.               ret                           ;exit
  977. create1:      call clear_window             ;clear the current display
  978.               xor al,al                     ;zero AL
  979.               call record_address           ;get address of empty record slot
  980.               mov slotno,al                 ;save position
  981.               mov al,32                     ;blank the record
  982.               mov cx,192
  983.               rep stosb
  984.               sub di,192                    ;point DI back to start of record
  985.               push di                       ;save address
  986.               mov si,offset menuline3       ;set text address
  987.               call edit_record              ;allow record to be edited
  988.               pop si                        ;get address in SI
  989.               jc blank_entry                ;branch if new entry is blank
  990.               call find_position            ;determine new record position
  991.               mov bl,slotno                 ;retrieve its physical position
  992.               call insert_record            ;insert new record into stack
  993.               mov recptr,cl                 ;point RECPTR to new record
  994.               ret
  995. blank_entry:  cmp numrec,0                  ;any records?
  996.               je blank1                     ;no, then exit
  997.               call show_record              ;display current record
  998. blank1:       ret
  999. create        endp
  1000. ;
  1001. ;------------------------------------------------------------------------------
  1002. ;DELETE deletes the current record.
  1003. ;------------------------------------------------------------------------------
  1004. delete        proc near
  1005.               cmp numrec,0                  ;any records to delete?
  1006.               je del_exit                   ;no, then exit
  1007.               mov si,offset menuline2       ;request verification
  1008.               call write_menu
  1009. del1:         call getkey                   ;get keyboard response
  1010.               cmp al,13                     ;ENTER pressed?
  1011.               je del2                       ;yes, then continue
  1012.               cmp al,27                     ;ESC pressed?
  1013.               jne del1                      ;no, then get another keypress
  1014. del2:         push ax                       ;save response
  1015.               mov si,offset menuline1       ;restore menu line
  1016.               call write_menu
  1017.               pop ax                        ;retrieve response
  1018.               cmp al,13                     ;delete the record?
  1019.               jne del_exit                  ;no
  1020.               call delete_record            ;delete current record
  1021.               cmp numrec,0                  ;any records left?
  1022.               jne del3                      ;yes, then branch
  1023.               call clear_window             ;no, then clear display
  1024. del_exit:     ret                           ;exit
  1025. del3:         mov al,numrec                 ;get record count
  1026.               cmp al,recptr                 ;is RECPTR in range?
  1027.               jae del4                      ;yes, then branch
  1028.               dec recptr                    ;no, then make sure it is
  1029. del4:         call show_record              ;display new current record
  1030.               ret
  1031. delete        endp
  1032. ;
  1033. ;------------------------------------------------------------------------------
  1034. ;SAVE writes the data in memory to disk.
  1035. ;------------------------------------------------------------------------------
  1036. save          proc near
  1037.               cmp numrec,0                  ;any records to save?
  1038.               jne fsave1                    ;yes, then continue
  1039.               ret                           ;no, then exit
  1040. fsave1:       cmp fileflag,0                ;does a filespec exist?
  1041.               jne fsave2                    ;yes, then branch
  1042. ;
  1043. ;Read a filespec input from the keyboard.
  1044. ;
  1045. getname:      mov si,offset menuline13      ;print input prompt
  1046.               call write_menu
  1047.               xor di,di                     ;prepare for call to READLN
  1048.               mov dx,0E1Ah
  1049.               mov cl,34
  1050.               call readln                   ;read the filespec
  1051.               or cl,cl                      ;anything entered?
  1052.               je save_exit                  ;no, then exit
  1053.               mov fileflag,1                ;set filespec indicator
  1054.               xor si,si                     ;copy filespec into buffer
  1055.               mov di,offset filespec
  1056.               xor ch,ch
  1057.               rep movsb
  1058.               mov byte ptr es:[di],0        ;zero last byte
  1059. ;
  1060. ;Open the file and write record data out to it.
  1061. ;
  1062. fsave2:       mov dx,offset filespec        ;point DX to filespec
  1063.               mov ah,3Ch                    ;open/create file
  1064.               xor cx,cx                     ;normal attributes
  1065.               int 21h
  1066.               jc getname                    ;get new filespec if open failed
  1067. fsave3:       mov bx,ax                     ;transfer file handle to BX
  1068.               mov ah,40h                    ;write NUMREC byte to file
  1069.               mov cx,1
  1070.               mov dx,offset numrec
  1071.               int 21h
  1072.               jc save_error                 ;branch on error
  1073.               cmp ax,1                      ;byte successfully written?
  1074.               jb diskfull                   ;no, then disk is full
  1075.               mov al,1                      ;initialize record number
  1076.               mov cl,numrec                 ;get number of records to write
  1077.               xor ch,ch
  1078. fsave4:       push cx                       ;save count
  1079.               push ax                       ;save record number
  1080.               call record_address           ;get address of current record
  1081.               mov dx,di                     ;transfer it to DX
  1082.               mov cx,192                    ;192 bytes per record
  1083.               mov ah,40h                    ;write one record
  1084.               int 21h
  1085.               mov dx,ax                     ;transfer byte count to DX
  1086.               pop ax                        ;retrieve record number and count
  1087.               pop cx
  1088.               jc save_error                 ;branch on error
  1089.               cmp dx,192                    ;entire record written?
  1090.               jb diskfull                   ;no, then disk is full
  1091.               inc al                        ;next record
  1092.               loop fsave4                   ;loop until done
  1093. closefile:    mov ah,3Eh                    ;close file
  1094.               int 21h
  1095. save_exit:    mov si,offset menuline1       ;restore menu line
  1096.               call write_menu
  1097.               ret                           ;exit
  1098. ;
  1099. ;An error was encountered during the save.
  1100. ;
  1101. save_error:   mov si,offset menuline11      ;print error message
  1102.               push bx                       ;save file handle
  1103.               call write_menu
  1104.               pop bx                        ;retrieve file handle
  1105. error2:       call getkey                   ;wait for a press of ESC
  1106.               cmp al,27
  1107.               jne error2
  1108.               jmp short closefile           ;close file and resume
  1109. ;
  1110. ;No room left on the disk.
  1111. ;
  1112. diskfull:     mov si,offset menuline8       ;print 'Disk full' message
  1113.               push bx                       ;save file handle
  1114.               call write_menu
  1115.               pop bx                        ;retrieve file handle
  1116. full2:        call getkey                   ;wait for a press of ESC
  1117.               cmp al,27
  1118.               jne full2
  1119.               jmp short closefile           ;and exit
  1120. save          endp
  1121. ;
  1122. ;------------------------------------------------------------------------------
  1123. ;DISABLE_CGA and ENABLE_CGA disable and enable CGA video output.
  1124. ;------------------------------------------------------------------------------
  1125. disable_cga   proc near
  1126.               mov dx,3DAh                   ;address of Status Register
  1127. disable1:     in al,dx                      ;get status
  1128.               test al,8                     ;vertical retrace active?
  1129.               je disable1                   ;no, then wait
  1130.               sub dx,2                      ;MSR address in DX
  1131.               mov al,25h                    ;value to disable video
  1132.               out dx,al                     ;disable video output
  1133.               ret
  1134. disable_cga   endp
  1135. ;
  1136. enable_cga    proc near
  1137.               mov ah,15                     ;get video mode
  1138.               int 10h
  1139.               mov bx,offset enable_values   ;get value to enable display
  1140.               xlat                          ;value in AL
  1141.               mov dx,3D8h                   ;MSR address
  1142.               out dx,al                     ;enable video output
  1143.               ret
  1144. enable_cga    endp
  1145. ;
  1146. ;------------------------------------------------------------------------------
  1147. ;GETKEY waits for a keypress and returns the keycode in AX.
  1148. ;Exit:  AX - keycode
  1149. ;------------------------------------------------------------------------------
  1150. getkey        proc near
  1151.               mov ah,1                      ;check keyboard buffer
  1152.               int 16h
  1153.               jne getkey1                   ;jump if buffer contains a keycode
  1154.               int 28h                       ;no key pressed - issue int 28h
  1155.               jmp getkey                    ;loop back to try again
  1156. getkey1:      mov ah,0                      ;get keycode from buffer
  1157.               int 16h
  1158.               ret                           ;exit with keycode in AX
  1159. getkey        endp
  1160. ;
  1161. ;------------------------------------------------------------------------------
  1162. ;INSERT_RECORD inserts a record into the stack.
  1163. ;Entry:  BL - slot number
  1164. ;        CL - index number
  1165. ;------------------------------------------------------------------------------
  1166. insert_record proc near
  1167.               push cx                       ;save index number
  1168.               mov di,offset index_table     ;point DI to index table
  1169.               mov al,cl                     ;get index number in AL for search
  1170.               mov cl,maxrec                 ;set counter
  1171.               xor ch,ch
  1172. insert1:      cmp [di],al                   ;index less than new index?
  1173.               jb insert2                    ;yes, then branch
  1174.               inc byte ptr [di]             ;increment index
  1175. insert2:      inc di                        ;advance DI to next index
  1176.               loop insert1                  ;loop until all indexes examined
  1177.               pop cx                        ;retrieve new index number
  1178.               xor bh,bh                     ;byte to word in BX
  1179.               mov di,offset index_table     ;point DI to index table
  1180.               mov [di+bx],cl                ;deposit new index into table
  1181.               inc numrec                    ;increment record count by 1
  1182.               ret
  1183. insert_record endp
  1184. ;
  1185. ;------------------------------------------------------------------------------
  1186. ;DELETE_RECORD deletes the record indexed by RECPTR.
  1187. ;------------------------------------------------------------------------------
  1188. delete_record proc near
  1189.               mov al,recptr                 ;search for current record slot
  1190.               mov di,offset index_table
  1191.               mov cl,maxrec
  1192.               xor ch,ch
  1193.               repne scasb
  1194.               dec di                        ;back to matching byte
  1195.               mov byte ptr [di],0           ;zero current index
  1196.               mov al,recptr                 ;get current record number
  1197.               mov di,offset index_table            ;point DI to index table
  1198.               mov cl,maxrec                 ;set counter
  1199.               xor ch,ch
  1200. delrec1:      cmp [di],al                   ;index less than current index?
  1201.               jb delrec2                    ;yes, then branch
  1202.               dec byte ptr [di]             ;no, decrement index
  1203. delrec2:      inc di                        ;advance to next index
  1204.               loop delrec1                  ;loop until all records examined
  1205.               dec numrec                    ;decrement record count by 1
  1206.               ret
  1207. delete_record endp
  1208. ;
  1209. ;------------------------------------------------------------------------------
  1210. ;EDIT_RECORD allows the record addressed by ES:DI to be edited.
  1211. ;Entry:  ES:DI - record address        | Exit:  CF clear - record valid
  1212. ;        DS:SI - menu line text string |        CF set   - record blank
  1213. ;------------------------------------------------------------------------------
  1214. edit_record   proc near
  1215.               push di                       ;save starting address
  1216.               call write_menu               ;write new menu line
  1217.               mov bh,video_page             ;set BH for video calls
  1218.               mov ah,2                      ;set initial cursor position
  1219.               mov dx,071Bh
  1220.               int 10h
  1221.               call show_cursor              ;display the cursor
  1222. ;
  1223. ;Wait for a keypress.
  1224. ;
  1225. editrec1:     call getkey                   ;get a keypress
  1226.               or al,al                      ;extended code?
  1227.               jne editrec2                  ;no, then branch
  1228.               jmp short extend              ;goto extended code handler
  1229. editrec2:     cmp al,8                      ;backspace key?
  1230.               je bspace
  1231.               cmp al,13                     ;ENTER key?
  1232.               je enter
  1233.               cmp al,32                     ;ASCII code less than 32?
  1234.               jb editrec1                   ;yes, then ignore it
  1235. ;
  1236. ;Process a press of a character key.
  1237. ;
  1238.               cmp dl,59                     ;at the end of the line?
  1239.               je editrec1                   ;yes, then ignore keypress
  1240.               stosb                         ;deposit character in record
  1241.               mov ah,10                     ;then print it
  1242.               mov cx,1
  1243.               int 10h
  1244.               mov ah,2                      ;advance the cursor
  1245.               inc dl
  1246.               int 10h
  1247.               jmp editrec1                  ;return for more
  1248. ;
  1249. ;Process a press of the BACKSPACE key.
  1250. ;
  1251. bspace:       cmp dl,27                     ;any characters to delete?
  1252.               je editrec1                   ;no, then ignore keypress
  1253.               mov ah,2                      ;move cursor back one space
  1254.               dec dl
  1255.               int 10h
  1256.               mov ax,0A20h                  ;print a space character
  1257.               mov cx,1
  1258.               int 10h
  1259.               dec di                        ;decrement buffer pointer by 1
  1260.               mov byte ptr es:[di],32       ;insert an ASCII space
  1261.               jmp editrec1
  1262. ;
  1263. ;Process a press of the ENTER key.
  1264. ;
  1265. enter:        mov al,dl                     ;reset DI to beginning of line
  1266.               xor ah,ah
  1267.               sub ax,27
  1268.               sub di,ax
  1269.               inc dh                        ;advance row number
  1270.               add di,32                     ;advance pointer
  1271.               cmp dh,13                     ;wrap around if necessary
  1272.               jne enter1
  1273.               mov dh,7
  1274.               sub di,192
  1275. enter1:       mov dl,27                     ;home the cursor
  1276.               mov ah,2
  1277.               int 10h
  1278.               jmp editrec1                  ;return to input loop
  1279. ;
  1280. ;Process a press of either Cursor-Left or Cursor-Right.
  1281. ;
  1282. extend:       cmp ah,75                     ;cursor left key?
  1283.               jne ext2                      ;no, then branch
  1284.               cmp dl,27                     ;already at left end of field?
  1285.               je ext1                       ;yes, then ignore keypress
  1286.               mov ah,2                      ;move cursor back one space
  1287.               dec dl
  1288.               int 10h
  1289.               dec di                        ;decrement buffer pointer
  1290. ext1:         jmp editrec1                  ;return
  1291. ext2:         cmp ah,77                     ;cursor right key?
  1292.               jne ext3                      ;no, then branch
  1293.               cmp dl,59                     ;cursor in last column?
  1294.               je ext1                       ;yes, then ignore keypress
  1295.               mov ah,2                      ;advance cursor
  1296.               inc dl
  1297.               int 10h
  1298.               inc di                        ;increment buffer pointer
  1299.               jmp editrec1                  ;return
  1300. ;
  1301. ;Process a press of either Cursor-Up or Cursor-Down.
  1302. ;
  1303. ext3:         cmp ah,72                     ;cursor up key?
  1304.               jne ext5                      ;no, then branch
  1305.               dec dh                        ;decrement row number
  1306.               sub di,32                     ;set pointer to previous line
  1307.               cmp dh,6                      ;wrap around if necessary
  1308.               jne ext4
  1309.               mov dh,12
  1310.               add di,192
  1311. ext4:         mov ah,2                      ;move the cursor
  1312.               int 10h
  1313.               jmp editrec1                  ;return for another keypress
  1314. ext5:         cmp ah,80                     ;cursor down key?
  1315.               jne ext6                      ;no, then branch
  1316.               inc dh                        ;increment row number
  1317.               add di,32                     ;set pointer to next line
  1318.               cmp dh,13                     ;wrap around if necessary
  1319.               jne ext4
  1320.               mov dh,7
  1321.               sub di,192
  1322.               jmp ext4                      ;move cursor and return
  1323. ;
  1324. ;End the edit routine when F1 is pressed.
  1325. ;
  1326. ext6:         cmp ah,59                     ;F1 key?
  1327.               jne ext4                      ;no, then ignore keypress
  1328.               mov ah,1                      ;hide the cursor
  1329.               mov ch,20h
  1330.               int 10h
  1331.               mov si,offset menuline1       ;restore menu line
  1332.               call write_menu
  1333.               pop di                        ;recover starting address
  1334.               mov al,32                     ;ASCII space character
  1335.               mov cx,192                    ;192 bytes per record
  1336.               repe scasb                    ;check for non-space character
  1337.               jne ok                        ;OK if non-space found
  1338.               stc                           ;set CF to indicate blank entry
  1339.               ret
  1340. ok:           clc                           ;clear CF to indicate valid record
  1341.               ret
  1342. edit_record   endp
  1343. ;
  1344. ;------------------------------------------------------------------------------
  1345. ;FIND_POSITION returns the new index of the record addressed by SI.
  1346. ;Entry:  SI - record address           | Exit:  CL - record number
  1347. ;------------------------------------------------------------------------------
  1348. find_position proc near
  1349.               mov cl,1                      ;set index for first record
  1350.               cmp numrec,0                  ;any records to examine?
  1351.               je find_exit                  ;no, then exit
  1352. find1:        mov al,cl                     ;get index in AL
  1353.               push cx                       ;save it
  1354.               call record_address           ;get address of next record
  1355.               push si                       ;save new record address
  1356.               mov cx,32                     ;32 bytes per record
  1357. find2:        cmpsb                         ;compare records
  1358.               ja next_record                ;check next record
  1359.               jb slot_found                 ;alphabetical slot found
  1360.               loop find2                    ;goto next byte if these are equal
  1361.               jmp short slot_found          ;slot found if all equal
  1362. next_record:  pop si                        ;clean up the stack
  1363.               pop cx
  1364.               inc cl                        ;next record number
  1365.               cmp cl,numrec                 ;all records searched?
  1366.               jbe find1                     ;no, then loop back for more
  1367. find_exit:    ret                           ;yes, then we're done
  1368. slot_found:   pop si                        ;clean up the stack
  1369.               pop cx
  1370.               ret
  1371. find_position endp
  1372. ;
  1373. ;------------------------------------------------------------------------------
  1374. ;SHOW_RECORD displays the record pointed to by RECPTR.
  1375. ;------------------------------------------------------------------------------
  1376. show_record   proc near
  1377.               mov al,recptr                 ;get current record number
  1378.               call record_address           ;get record address in DI
  1379.               mov si,di                     ;transfer it to SI
  1380.               mov bl,record_attr            ;set attribute to be used
  1381.               mov dx,071Bh                  ;set initial cursor position
  1382.               mov cx,6                      ;6 lines to display
  1383. show1:        push cx                       ;save line counter
  1384.               push dx                       ;save cursor position
  1385.               mov cx,32                     ;32 characters per line
  1386.               call writeln                  ;display one line
  1387.               pop dx                        ;retrieve cursor address
  1388.               inc dh                        ;increment row number
  1389.               pop cx                        ;retrieve line counter
  1390.               loop show1                    ;loop until done
  1391.               ret
  1392. show_record   endp
  1393. ;
  1394. ;------------------------------------------------------------------------------
  1395. ;RECORD_ADDRESS returns the offset address and slot number of a record.
  1396. ;Entry: AL - record number             | Exit:  DI - record address
  1397. ;                                      |        AL - slot number
  1398. ;------------------------------------------------------------------------------
  1399. record_address proc near
  1400.               mov di,offset index_table     ;point DI to index table
  1401.               mov cl,maxrec                 ;set counter
  1402.               xor ch,ch
  1403.               repne scasb                   ;search for current record number
  1404.               inc cx                        ;increment counter
  1405.               mov al,maxrec                 ;calculate offset address in AX
  1406.               sub al,cl
  1407.               push ax                       ;save slot number
  1408.               mul record_length
  1409.               add ax,offset data_buffer
  1410.               mov di,ax                     ;transfer address to DI
  1411.               pop ax                        ;recover slot number
  1412.               ret
  1413. record_address endp
  1414. ;
  1415. ;------------------------------------------------------------------------------
  1416. ;WRITE_MENU displays a line of text on the window's menu line.
  1417. ;Entry:  DS:SI - address of text
  1418. ;------------------------------------------------------------------------------
  1419. write_menu    proc near
  1420.               mov ah,2                      ;position the cursor
  1421.               mov dx,0E14h
  1422.               mov bh,video_page
  1423.               int 10h
  1424.               mov ax,0920h                  ;erase current menu line
  1425.               mov bl,menu_attr
  1426.               mov cx,40
  1427.               int 10h
  1428. wm1:          lodsb                         ;get a character
  1429.               or al,al                      ;exit if it's the delimiter
  1430.               je wm2
  1431.               mov ah,0Eh                    ;write the character
  1432.               int 10h
  1433.               jmp short wm1                 ;loop until done
  1434. wm2:          ret
  1435. write_menu    endp
  1436. ;
  1437. ;------------------------------------------------------------------------------
  1438. ;WRITELN displays a string.
  1439. ;Entry:  DS:SI - string address
  1440. ;        BL    - attribute
  1441. ;        CX    - string length
  1442. ;        DH,DL - starting row and column
  1443. ;------------------------------------------------------------------------------
  1444. writeln       proc near
  1445.               mov bh,video_page             ;set page number for output
  1446. write1:       mov ah,2                      ;position cursor
  1447.               int 10h
  1448.               lodsb                         ;get one byte
  1449.               push cx                       ;save count
  1450.               mov cx,1                      ;zero repetitions
  1451.               mov ah,9                      ;int 10h function - write c/a
  1452.               int 10h                       ;write character/attribute
  1453.               inc dl                        ;advance cursor
  1454.               pop cx                        ;retrieve character count
  1455.               loop write1                   ;loop until done
  1456.               ret
  1457. writeln       endp
  1458. ;
  1459. ;------------------------------------------------------------------------------
  1460. ;READLN accepts input of a string entered from the keyboard.
  1461. ;Entry:  ES:DI - buffer address        | Exit: CL - string length
  1462. ;        DH,DL - cursor start position |
  1463. ;        CL    - max length accepted   |
  1464. ;------------------------------------------------------------------------------
  1465. maxlen        db ?                          ;maximum string length
  1466. ;
  1467. readln        proc near
  1468.               mov maxlen,cl                 ;save max length
  1469.               mov ah,2                      ;set cursor to start position
  1470.               mov bh,video_page
  1471.               int 10h
  1472.               call show_cursor              ;display the cursor
  1473.               xor cl,cl                     ;initialize counter
  1474. ;
  1475. ;Wait for a keypress.
  1476. ;
  1477. read1:        call getkey                   ;get a character
  1478.               cmp al,13                     ;ENTER key?
  1479.               je read_exit                  ;yes, then exit
  1480.               cmp al,27                     ;ESC key?
  1481.               jne read2                     ;no, then branch
  1482.               xor cl,cl                     ;zero length
  1483.               jmp short read_exit           ;exit
  1484. read2:        cmp al,8                      ;backspace key?
  1485.               je backspace                  ;yes, then do backspace function
  1486.               cmp al,32                     ;ASCII 32 or greater?
  1487.               jb read1                      ;no, then ignore it
  1488.               cmp al,126                    ;ASCII 126 or less?
  1489.               ja read1                      ;no, then ignore keypress
  1490.               cmp cl,maxlen                 ;room for another entry?
  1491.               je read1                      ;no, then ignore it
  1492. ;
  1493. ;Process the press of a character key.
  1494. ;
  1495.               stosb                         ;deposit character in buffer
  1496.               push cx                       ;save character count
  1497.               mov ah,10                     ;print the character
  1498.               mov cx,1
  1499.               int 10h
  1500.               inc dl                        ;advance the cursor
  1501.               mov ah,2
  1502.               int 10h
  1503.               pop cx                        ;retrieve count
  1504.               inc cl                        ;update count
  1505.               jmp read1                     ;go back for more
  1506. ;
  1507. ;Process a press of the BACKSPACE key.
  1508. ;
  1509. backspace:    or cl,cl                      ;any characters to delete?
  1510.               je read1                      ;no, then ignore keystroke
  1511.               push cx                       ;save count
  1512.               dec dl                        ;move cursor back one space
  1513.               mov ah,2
  1514.               int 10h
  1515.               mov ah,10                     ;print a space character
  1516.               mov al,32
  1517.               mov cx,1
  1518.               int 10h
  1519.               pop cx                        ;retrieve count
  1520.               dec cl                        ;decrement it
  1521.               dec di                        ;decrement buffer pointer
  1522.               jmp read1                     ;go back for more
  1523. ;
  1524. ;Hide the cursor and return.
  1525. ;
  1526. read_exit:    mov ah,1                      ;hide the cursor
  1527.               mov ch,20h
  1528.               int 10h
  1529.               ret
  1530. readln        endp
  1531. ;
  1532. ;------------------------------------------------------------------------------
  1533. ;SHOW_CURSOR displays the cursor and discounts EGA cursor emulation logic.
  1534. ;Entry:  NEW_CURSOR - starting and ending scan lines
  1535. ;------------------------------------------------------------------------------
  1536. show_cursor   proc near
  1537.               cmp adapter,2                 ;is an EGA currently active?
  1538.               jne cursor1                   ;no, then branch
  1539.               push es                       ;save ES
  1540.               mov ax,bios_data              ;point ES to BIOS data area
  1541.               mov es,ax
  1542.               assume es:bios_data
  1543.               push infobyte                 ;save EGA info byte
  1544.               or ega_info,1                 ;disable EGA cursor emulation
  1545. cursor1:      mov ah,1                      ;display the cursor
  1546.               mov cx,new_cursor
  1547.               int 10h
  1548.               cmp adapter,2                 ;is an EGA active?
  1549.               jne cursor_exit               ;no, then exit
  1550.               pop infobyte                  ;restore EGA info byte
  1551.               pop es                        ;restore ES
  1552.               assume es:nothing
  1553. cursor_exit:  ret
  1554. show_cursor   endp
  1555. ;
  1556. ;------------------------------------------------------------------------------
  1557. ;CLEAR_WINDOW clears the record currently displayed in the window.
  1558. ;------------------------------------------------------------------------------
  1559. clear_window  proc near
  1560.               mov ax,0600h                  ;interrupt 10h, function 6
  1561.               mov cx,071Bh
  1562.               mov dx,0C3Bh
  1563.               mov bh,record_attr
  1564.               int 10h
  1565.               ret
  1566. clear_window  endp
  1567. ;
  1568. ;------------------------------------------------------------------------------
  1569. ;IOSET vectors interrupts 1Bh, 23h and 24h to internal handlers.  IORESET
  1570. ;restores the original vector values.
  1571. ;------------------------------------------------------------------------------
  1572. ioset         proc near
  1573.               push es                       ;save ES
  1574.               mov ax,351Bh                  ;get interrupt 1Bh vector
  1575.               int 21h
  1576.               mov old1Bh_segment,es         ;save it
  1577.               mov old1Bh_offset,bx
  1578.               mov ah,25h                    ;point it to an IRET instruction
  1579.               mov dx,offset ioexit
  1580.               int 21h
  1581.               mov ax,3523h                  ;get interrupt 23h vector
  1582.               int 21h
  1583.               mov old23h_segment,es         ;save it
  1584.               mov old23h_offset,bx
  1585.               mov ah,25h                    ;point it to an IRET instruction
  1586.               mov dx,offset ioexit
  1587.               int 21h
  1588.               mov ax,3524h                  ;get interrupt 24h vector
  1589.               int 21h
  1590.               mov old24h_segment,es         ;save it
  1591.               mov old24h_offset,bx
  1592.               mov ah,25h                    ;then set it to IOERR routine
  1593.               mov dx,offset ioerr
  1594.               int 21h
  1595.               pop es                        ;restore ES
  1596.               ret
  1597. ioset         endp
  1598. ;
  1599. ioreset       proc near
  1600.               mov ax,2524h                  ;restore interrupt 24h vector
  1601.               mov dx,old24h_offset
  1602.               push ds
  1603.               assume ds:nothing
  1604.               mov ds,old24h_segment
  1605.               int 21h
  1606.               mov ax,2523h                  ;restore interrupt 23h vector
  1607.               mov dx,old23h_offset
  1608.               mov ds,old23h_segment
  1609.               int 21h
  1610.               mov ax,251Bh                  ;restore interrupt 1Bh vector
  1611.               mov dx,old1Bh_offset
  1612.               mov ds,old1Bh_segment
  1613.               int 21h
  1614.               pop ds
  1615.               assume ds:code
  1616.               ret
  1617. ioreset       endp
  1618. ;
  1619. ;------------------------------------------------------------------------------
  1620. ;FINISH loads the data file, resets interrupt vectors, and terminates.
  1621. ;------------------------------------------------------------------------------
  1622. finish        proc near
  1623. ;
  1624. ;Open the specified data file for reading.
  1625. ;
  1626.               mov ax,3D00h                  ;open file for reading
  1627.               mov dx,offset filespec        ;point DX to ASCIIZ filespec
  1628.               int 21h
  1629.               jnc finish3                   ;branch if no error
  1630.               mov ah,9                      ;print 'File not found'
  1631.               mov dx,offset errmsg1
  1632.               int 21h
  1633.               cmp reload,0                  ;was this an attempted reload?
  1634.               je endfin                     ;no, then exit
  1635.               mov al,old_numrec             ;yes, then restore parameters
  1636.               mov es:[numrec],al
  1637.               mov al,old_recptr
  1638.               mov es:[recptr],al
  1639.               mov al,old_fileflag
  1640.               mov es:[fileflag],al
  1641. endfin:       ret                           ;and exit
  1642. ;
  1643. ;Load the data file into memory.
  1644. ;
  1645. finish3:      mov bx,ax                     ;transfer file handle to BX
  1646.               push ds                       ;exchange DS and ES
  1647.               push es
  1648.               pop ds
  1649.               pop es
  1650.               mov ah,3Fh                    ;read record count byte
  1651.               mov cx,1
  1652.               mov dx,offset numrec
  1653.               int 21h
  1654.               jc close                      ;branch on error
  1655.               mov al,ds:[maxrec]            ;make sure NUMREC <= MAXREC
  1656.               cmp al,ds:[numrec]
  1657.               jae finish4
  1658.               mov ds:[numrec],al            ;adjust if it isn't
  1659. finish4:      mov al,ds:[numrec]            ;calculate number of bytes to read
  1660.               mul record_length
  1661.               mov cx,ax                     ;transfer number of bytes to CX
  1662.               mov ah,3Fh                    ;DOS function 3Fh - read file
  1663.               mov dx,offset data_buffer     ;point DX to buffer area
  1664.               int 21h                       ;read all records from disk
  1665. close:        mov ah,3Eh                    ;close file
  1666.               int 21h
  1667.               mov ds:[fileflag],1           ;set filespec flag
  1668.               push ds                       ;swap DS and ES again
  1669.               push es
  1670.               pop ds
  1671.               pop es
  1672. ;
  1673. ;Initialize the record index table.
  1674. ;
  1675. finish5:      mov di,offset index_table     ;point DI to table area
  1676.               xor al,al                     ;zero AL
  1677.               mov cl,es:[maxrec]            ;set counter
  1678.               xor ch,ch
  1679.               rep stosb                     ;zero all bytes
  1680.               mov cl,es:[numrec]            ;set CX to number of records
  1681.               xor ch,ch
  1682.               jcxz finish7                  ;exit if there are none
  1683.               mov di,offset index_table     ;reset DI
  1684.               mov al,1                      ;initialize AL
  1685. finish6:      stosb                         ;set one index byte
  1686.               inc al                        ;increment index
  1687.               loop finish6                  ;loop until done
  1688. ;
  1689. ;Copy new filespec into old data space if this is a reload.
  1690. ;
  1691. finish7:      cmp reload,0                  ;is this a reload
  1692.               je finish8                    ;no, then branch
  1693.               mov si,offset filespec        ;point SI and DI to filespec areas
  1694.               mov di,si
  1695.               mov cx,126                    ;set counter
  1696.               rep movsb                     ;transfer text
  1697.               ret                           ;done - exit
  1698. ;
  1699. ;Save and replace all required interrupt vectors.
  1700. ;
  1701. finish8:      mov ax,3508h                  ;get interrupt 8 vector
  1702.               int 21h
  1703.               mov old8h,bx                  ;save it
  1704.               mov old8h[2],es
  1705.               mov ah,25h                    ;point it to the TIMER routine
  1706.               mov dx,offset timer
  1707.               int 21h
  1708.               mov ax,3509h                  ;get interrupt 9 vector
  1709.               int 21h
  1710.               mov old9h,bx                  ;save it
  1711.               mov old9h[2],es
  1712.               mov ah,25h                    ;point it to KEYBOARD routine
  1713.               mov dx,offset keyboard
  1714.               int 21h
  1715.               mov ax,3510h                  ;get interrupt 10h vector
  1716.               int 21h
  1717.               mov old10h,bx                 ;save it
  1718.               mov old10h[2],es
  1719.               mov ah,25h                    ;point it to VIDEO
  1720.               mov dx,offset video
  1721.               int 21h
  1722.               mov ax,3513h                  ;get interrupt 13h vector
  1723.               int 21h
  1724.               mov old13h,bx                 ;save it
  1725.               mov old13h[2],es
  1726.               mov ah,25h                    ;point it to BDISK
  1727.               mov dx,offset bdisk
  1728.               int 21h
  1729.               mov ax,3528h                  ;get interrupt 28h vector
  1730.               int 21h
  1731.               mov old28h,bx                 ;save it
  1732.               mov old28h[2],es
  1733.               mov ah,25h                    ;point it to BACKPROC
  1734.               mov dx,offset backproc
  1735.               int 21h
  1736. ;
  1737. ;Calculate amount of memory to reserve and terminate-but-stay-resident.
  1738. ;
  1739.               mov dx,offset program         ;display notice and hot key
  1740.               mov ah,9                      ;with DOS function 9
  1741.               int 21h
  1742.               mov al,maxrec                 ;get max number of records
  1743.               mul record_length             ;multiply by 192
  1744.               mov dx,ax                     ;transfer figure to DX
  1745.  
  1746.               add dx,(offset data_buffer - offset code + 15)
  1747.  
  1748.               mov cl,4                      ;convert bytes to paragraphs
  1749.               shr dx,cl
  1750.               mov ax,3100h                  ;load function and return codes
  1751.               int 21h                       ;terminate-but-stay-resident
  1752. finish        endp
  1753. ;
  1754. ;-----------------------------------------------------------------------------
  1755. ;Data space to be used after Cardfile is resident in memory.
  1756. ;-----------------------------------------------------------------------------
  1757. pc            = $
  1758. screen_buffer = pc                          ;video memory buffer
  1759. pc            = pc + 10 * 44 * 2
  1760. index_table   = pc                          ;record index table
  1761. pc            = pc + 512
  1762. filespec      = pc                          ;file specification
  1763. pc            = pc + 128
  1764. data_buffer   = pc                          ;record buffer
  1765. ;
  1766. ;------------------------------------------------------------------------------
  1767. ;INITIALIZE prepares the program for residency.
  1768. ;------------------------------------------------------------------------------
  1769. initialize    proc near
  1770.               assume ds:code
  1771. errmsg1       db 13,10,"File not found",13,10,"$"
  1772. errmsg2       db 13,10,"Critical Error Flag not found",13,10,"$"
  1773. old_numrec    db ?
  1774. old_recptr    db ?
  1775. old_fileflag  db ?
  1776. ;
  1777. ;See if the program is already resident in memory.
  1778. ;
  1779. init1:        mov word ptr [begin],0        ;zero word to avoid false match
  1780.               xor bx,bx                     ;initialize search segment
  1781.               mov ax,cs                     ;record current segment in AX
  1782. init2:        inc bx                        ;increment search segment
  1783.               cmp ax,bx                     ;reached current segment?
  1784.               je init3                      ;yes, then this is the first load
  1785.               mov es,bx                     ;point ES to search segment
  1786.               mov si,offset begin           ;point SI and DI to ID offset
  1787.               mov di,si
  1788.               mov cx,16                     ;check 16 characters
  1789.               cld                           ;clear DF
  1790.               repe cmpsb                    ;compare the strings
  1791.               jne init2                     ;continue search if compare failed
  1792. ;
  1793. ;Cardfile is already installed.  Set the reload flag and save parameters.
  1794. ;
  1795.               mov reload,1                  ;set flag
  1796.               mov al,es:[numrec]            ;save parameters
  1797.               mov old_numrec,al
  1798.               mov al,es:[recptr]
  1799.               mov old_recptr,al
  1800.               mov al,es:[fileflag]
  1801.               mov old_fileflag,al
  1802.               mov es:[numrec],0             ;initialize counters and flags
  1803.               mov es:[recptr],1
  1804.               mov es:[fileflag],0
  1805.               jmp short parse                     ;branch to parsing code
  1806. ;
  1807. ;Determine which version of DOS is running.
  1808. ;
  1809. init3:        mov ah,30h                    ;DOS function 30h
  1810.               int 21h
  1811.               mov dos_version,al            ;major version number
  1812. ;
  1813. ;Get and save the address of the INDOS flag.
  1814. ;
  1815.               mov ah,34h                    ;function 34h
  1816.               int 21h                       ;get address
  1817.               mov dos_segment,es            ;save segment
  1818.               mov indos_offset,bx           ;save offset
  1819. ;
  1820. ;Get and save the address of the critical error flag.
  1821. ;
  1822.               mov ax,3E80h                  ;CMP opcode
  1823.               mov cx,2000h                  ;max search length
  1824.               mov di,bx                     ;start at INDOS address
  1825. init4:        repne scasw                   ;do the search
  1826.               jcxz init5                    ;branch if search failed
  1827.               cmp byte ptr es:[di+5],0BCh   ;verify this is it
  1828.               je found                      ;branch if it is
  1829.               jmp init4                     ;resume loop if it's not
  1830. init5:        mov cx,2000h                  ;search again
  1831.               inc bx                        ;search odd addresses this time
  1832.               mov di,bx
  1833. init6:        repne scasw                   ;look for the opcode
  1834.               jcxz notfound                 ;not found if loop expires
  1835.               cmp byte ptr es:[di+5],0BCh   ;verify this is it
  1836.               je found
  1837.               jmp init6
  1838. notfound:     mov ah,9                      ;flag not found
  1839.               mov dx,offset errmsg2
  1840.               int 21h
  1841.               ret
  1842. found:        mov ax,es:[di]                ;get flag offset address
  1843.               mov errflag_offset,ax         ;save it
  1844.               push cs                       ;reset ES to the code segment
  1845.               pop es
  1846. ;
  1847. ;Parse the command line and create a complete filespec.
  1848. ;
  1849. parse:        mov di,82h                    ;point DI to command line text
  1850.               cmp byte ptr [di-2],2         ;less than 2 characters entered?
  1851.               jnb parse0                    ;no, then continue
  1852.               jmp finish5                   ;yes, then skip load routine
  1853. parse0:       mov si,di                     ;point SI to command line text
  1854.               mov di,offset filespec        ;point DI to buffer
  1855. parse1:       cmp byte ptr [si],32          ;advance to first non-space
  1856.               jne parse2
  1857.               inc si
  1858.               jmp parse1
  1859. parse2:       cmp byte ptr [si+1],":"       ;leading drive specifier?
  1860.               je parse4                     ;yes, then filespec is complete
  1861.               mov ah,19h                    ;get current drive
  1862.               int 21h
  1863.               add al,65                     ;convert to ASCIIZ
  1864.               mov ah,":"                    ;complete drive specifier
  1865.               mov word ptr [di],ax          ;write drive spec to buffer
  1866.               add di,2                      ;advance DI
  1867.               cmp byte ptr [si],"\"         ;leading backslash?
  1868.               je parse4                     ;yes, then filespec is complete
  1869.               mov byte ptr [di],"\"         ;fill in the backslash
  1870.               inc di
  1871.               push si                       ;save SI and DI
  1872.               push di
  1873.               mov ah,47h                    ;get current path
  1874.               mov si,di
  1875.               xor dl,dl                     ;default drive
  1876.               int 21h                       ;append path to drive spec
  1877.               pop di                        ;restore SI and DI
  1878.               pop si
  1879.               cmp byte ptr [di],0           ;anything returned?
  1880.               je parse4                     ;no, then filespec is complete
  1881. parse3:       inc di                        ;advance to end of string
  1882.               cmp byte ptr [di],0
  1883.               jne parse3
  1884.               mov byte ptr [di],"\"         ;insert trailing backslash
  1885.               inc di
  1886. parse4:       mov al,[si]                   ;append entry to filespec string
  1887.               cmp al,13
  1888.               je parse5
  1889.               mov [di],al
  1890.               inc si
  1891.               inc di
  1892.               jmp parse4
  1893. parse5:       mov byte ptr [di],0
  1894.               jmp finish                    ;load data file and exit
  1895. initialize    endp
  1896. ;
  1897. code          ends
  1898.               end begin
  1899.